package com.handle.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.handle.common.core.constants.Constant;
import com.handle.common.core.enums.ValidateEnum;
import com.handle.common.core.exception.ValidateException;
import lombok.Data;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;

import java.net.URI;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author zhangqing
 * @version V1.0
 * @description 图片验证码过滤器
 * @date 7/12/2020 5:34 PM
 */
@Component
public class ImgCodeFilter extends AbstractGatewayFilterFactory<ImgCodeFilter.Config> {

    private final RedissonClient redissonClient;

    public ImgCodeFilter(RedissonClient redissonClient) {
        super(Config.class);
        this.redissonClient=redissonClient;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            URI uri = request.getURI();

            // 如果不是登录请求，直接放行
            if (!uri.getPath().equals(config.getExclude())) {
                return chain.filter(exchange);
            }
            String bodyStr = resolveBodyFromRequest(request);
            JSONObject bodyJson = JSONObject.parseObject(bodyStr);
            ValidateEnum.VALIDATE_INFO_NULL.assertIsEmpty(bodyJson);
            String code = (String) bodyJson.get("captcha");
            String randomStr = (String) bodyJson.get("randomStr");
            // 校验验证码
            checkCode(code, randomStr);
            return chain.filter(exchange);
        };
    }

    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
        // 获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        AtomicReference<String> bodyRef = new AtomicReference<>();
        body.subscribe(buffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
            DataBufferUtils.release(buffer);
            bodyRef.set(charBuffer.toString());
        });
        return bodyRef.get();
    }

    /**
     * 检查code
     *
     * @param code 运算结果
     * @param randomStr 验证码的唯一号
     */
    private void checkCode(String code, String randomStr) {
        ValidateEnum.VALIDATE_NULL.assertIsEmpty(code);
        ValidateEnum.VALIDATE_NOT_LEGAL.assertIsEmpty(randomStr);
        String key = Constant.DEFAULT_CODE_KEY + randomStr;
        RBucket<String> bucket = redissonClient.getBucket(key);
        String saveCode = bucket.get();
        bucket.delete();
        ValidateEnum.VALIDATE_LOSE_EFFICACY.assertIsEmpty(saveCode);
        ValidateEnum.VALIDATE_INCORRECTNESS.assertEquals(saveCode,code);
    }

    @Data
    static class Config {
        private String exclude;
    }
}
